package com.weijianhuawen.wjblog.web.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.weijianhuawen.wjblog.admin.event.ReadArticleEvent;
import com.weijianhuawen.wjblog.common.domain.dos.*;
import com.weijianhuawen.wjblog.common.domain.mapper.*;
import com.weijianhuawen.wjblog.common.enums.ResponseCodeEnum;
import com.weijianhuawen.wjblog.common.exception.BizException;
import com.weijianhuawen.wjblog.common.utils.PageResponse;
import com.weijianhuawen.wjblog.common.utils.Response;
import com.weijianhuawen.wjblog.web.convert.ArticleConvert;
import com.weijianhuawen.wjblog.web.markdown.MarkdownHelper;
import com.weijianhuawen.wjblog.web.mode.vo.article.*;
import com.weijianhuawen.wjblog.web.mode.vo.category.FindCategoryListRspVo;
import com.weijianhuawen.wjblog.web.mode.vo.tag.FindTagListRspVo;
import com.weijianhuawen.wjblog.web.service.ArticleService;
import com.weijianhuawen.wjblog.web.utils.MarkdownEscapedUtil;
import com.weijianhuawen.wjblog.web.utils.MarkdownStatsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @version: java version 8
 * @Author: weijianhuawen
 * @description:
 * @date: 2024-10-28 18:19
 */

@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {
    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private ArticleCategoryRelMapper articleCategoryRelMapper;
    @Resource
    private TagMapper tagMapper;
    @Resource
    private ArticleTagRelMapper articleTagRelMapper;
    @Resource
    private ArticleContentMapper articleContentMapper;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Override
    public PageResponse findIndexArticlePageList(FindIndexArticlePageListReqVo vo) {
        // 获取需要查询的页码与一页的数据量
        Long current = vo.getCurrent();
        Long size = vo.getSize();

        // 分页查询文章主体记录
        Page<ArticleDo> articleDoPage = articleMapper.selectPageList(current, size, null, null, null, null);

        // 返回分页数据
        List<ArticleDo> articleDoList = articleDoPage.getRecords();

        List<FindIndexArticlePageListRspVo> vos = null;
        // 将查询的数据转成vo
        if (!CollectionUtils.isEmpty(articleDoList)) {
            // 将do 转换 成 vo
            vos =  articleDoList.stream().map(tagDo -> {
                        FindIndexArticlePageListRspVo findIndexArticlePageListRspVo = ArticleConvert.INSTENCE.convertDoToVo(tagDo);
                        findIndexArticlePageListRspVo.setIsTop(tagDo.getWeight() > 0);
                        return findIndexArticlePageListRspVo;
                    }).collect(Collectors.toList());

            // 获取文章id集合
            List<Long> articleIds = articleDoList.stream().map(ArticleDo::getId).collect(Collectors.toList());

            // 查询文章所关联的分类
            List<CategoryDo> categoryDos = categoryMapper.selectList(Wrappers.emptyWrapper());
            // 转换为map
            Map<Long, String> categoryIdNameMap = categoryDos.stream().collect(Collectors.toMap(CategoryDo::getId, CategoryDo::getName));
            // 根据文章id查询关联的分类关联记录
            List<ArticleCategoryRelDo> articleCategoryRelDos = articleCategoryRelMapper.selectByArticleIds(articleIds);

            // 遍历所查询到的文章vo，为其设置category字段
            vos.forEach(item -> {
                // 获取当前文章id
                Long id = item.getId();

                // 根据该id筛选满足关联的分类
                Optional<ArticleCategoryRelDo> optional = articleCategoryRelDos.stream()
                        .filter(articleCategoryRelDo -> Objects.equals(articleCategoryRelDo.getArticleId(), id))
                        .findAny();

                if (optional.isPresent()) {
                    // 记录不为空则取出记录，并设置分类
                    ArticleCategoryRelDo articleCategoryRelDo = optional.get();
                    Long categoryId = articleCategoryRelDo.getCategoryId();
                    String categoryName = categoryIdNameMap.get(categoryId);

                    FindCategoryListRspVo findCategoryListRspVo = FindCategoryListRspVo.builder()
                            .id(categoryId)
                            .name(categoryName)
                            .build();

                    // 将category对象存入vo中
                    item.setCategory(findCategoryListRspVo);
                }
            });

            // 设置标签字段
            // 获取所有标签集合
            List<TagDo> tagDos = tagMapper.selectList(Wrappers.emptyWrapper());
            // 将tagid与name形成映射
            Map<Long, String> tagIdNameMap = tagDos.stream().collect(Collectors.toMap(TagDo::getId, TagDo::getName));

            // 获取所有文章标签关联记录
            List<ArticleTagRelDo> articleTagRelDos = articleTagRelMapper.selectByArticleIds(articleIds);

            // 遍历vo 设置tag字段
            vos.forEach(item -> {
                // 获取当前文章id
                Long id = item.getId();
                // 过滤出满足tagid关联文章id的关联记录
                List<ArticleTagRelDo> articleTagRelDoList = articleTagRelDos.stream()
                        .filter(articleTagRelDo -> Objects.equals(articleTagRelDo.getArticleId(), id))
                        .collect(Collectors.toList());

                // 设置tags字段
                List<FindTagListRspVo> findTagListRspVos = Lists.newArrayList();

                articleTagRelDoList.forEach(articleTagRelDo -> {
                    // 获取tagid
                    Long tagId = articleTagRelDo.getTagId();
                    // 获取tagname
                    String tagName = tagIdNameMap.get(tagId);

                    FindTagListRspVo findTagListRspVo = FindTagListRspVo.builder()
                            .id(tagId)
                            .name(tagName)
                            .build();

                    findTagListRspVos.add(findTagListRspVo);
                });
                // 设置tags字段
                item.setTags(findTagListRspVos);
            });
        }

        return PageResponse.success(articleDoPage, vos);
    }

    @Override
    public Response findArticleDetailForMarkdown(FindArticleDetailReqVo vo) {
        // 获取文章id
        Long articleId = vo.getArticleId();

        // 查询文章表，判断该文章是否存在
        ArticleDo articleDo = articleMapper.selectByArticleId(articleId);

        // 文章不存在
        if (Objects.isNull(articleDo)) {
            log.warn("【前台文章服务】文章id：{} 不存在或已被删除", articleId);
            throw new BizException(ResponseCodeEnum.NOT_EXIST_ARTICLE_ERROR);
        }

        // 将do转换为vo
        FindArticleDetailRspVo findArticleDetailRspVo = FindArticleDetailRspVo.builder()
                .id(articleId)
                .cover(articleDo.getCover())
                .title(articleDo.getTitle())
                .createTime(articleDo.getCreateTime())
                .updateTime(articleDo.getUpdateTime())
                .summary(articleDo.getSummary())
                .readNum(articleDo.getReadNum())
                .build();

        // 查询正文
        ArticleContentDo articleContentDo = articleContentMapper.selectByArticleId(articleId);
        // 转入vo
        findArticleDetailRspVo.setContent(articleContentDo.getContent());
        // 查询分类， 找到该文章所关联的分类
        ArticleCategoryRelDo articleCategoryRelDo = articleCategoryRelMapper.selectByArticleId(articleId);
        CategoryDo categoryDo = CategoryDo.builder().build();
        if (Objects.isNull(articleCategoryRelDo)) {
            log.info("【前台文章服务】 文章id:{} 不存在对应分类关联", articleId);
        } else {
            // 查询文章表
            categoryDo = categoryMapper.selectById(articleCategoryRelDo.getCategoryId());
        }
        //转入vo
        findArticleDetailRspVo.setCategoryName(categoryDo.getName());
        findArticleDetailRspVo.setCategoryId(categoryDo.getId());

        // 查询关联标签
        List<ArticleTagRelDo> articleTagRelDos = articleTagRelMapper.selectByArticleId(articleId);
        List<Long> tagIds = Lists.newArrayList();
        if (Objects.nonNull(articleTagRelDos)) {
            tagIds = articleTagRelDos.stream().map(ArticleTagRelDo::getTagId).collect(Collectors.toList());
        }
        // 查询所有标签
        List<TagDo> tagDos = tagMapper.selectListByTagIds(tagIds);

        // 转入vo
        List<FindTagListRspVo> findTagListRspVos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(tagDos)) {
            findTagListRspVos = tagDos.stream()
                    .map(tagDo -> FindTagListRspVo.builder().id(tagDo.getId()).name(tagDo.getName()).build())
                    .collect(Collectors.toList());

        }
        findArticleDetailRspVo.setTags(findTagListRspVos);

        // 上一篇文章
        ArticleDo preDo = articleMapper.selectPreArticleById(articleId);
        // 下一篇文章
        ArticleDo nextDo = articleMapper.selectNextArticleById(articleId);
        // 计算词数
        Integer wordCount = MarkdownStatsUtil.calculateWordCount(articleContentDo.getContent());
        // 估算阅读时间
        String readTime = MarkdownStatsUtil.calculateReadingTime(wordCount);
        // 转换为vo
        if (Objects.nonNull(preDo)) {
            FindPreNextArticleRspVo preVo = FindPreNextArticleRspVo.builder()
                    .articleId(preDo.getId())
                    .title(preDo.getTitle())
                    .build();

            findArticleDetailRspVo.setPreArticle(preVo);
        }
        if (Objects.nonNull(nextDo)) {
            FindPreNextArticleRspVo nextVo = FindPreNextArticleRspVo.builder()
                    .articleId(nextDo.getId())
                    .title(nextDo.getTitle())
                    .build();

            findArticleDetailRspVo.setNextArticle(nextVo);
        }
        findArticleDetailRspVo.setReadTime(readTime);
        findArticleDetailRspVo.setTotalWords(wordCount);
        // 通过事件订阅，将阅读量+1 发布事件
        applicationEventPublisher.publishEvent(new ReadArticleEvent(this, articleId));
        return Response.success(findArticleDetailRspVo);
    }

    @Override
    public Response findArticleDetailForHTML(FindArticleDetailReqVo vo) {
        // 获取文章id
        Long articleId = vo.getArticleId();

        // 查询文章表，判断该文章是否存在
        ArticleDo articleDo = articleMapper.selectByArticleId(articleId);

        // 文章不存在
        if (Objects.isNull(articleDo)) {
            log.warn("【前台文章服务】文章id：{} 不存在或已被删除", articleId);
            throw new BizException(ResponseCodeEnum.NOT_EXIST_ARTICLE_ERROR);
        }

        // 将do转换为vo
        FindArticleDetailRspVo findArticleDetailRspVo = FindArticleDetailRspVo.builder()
                .id(articleId)
                .cover(articleDo.getCover())
                .title(articleDo.getTitle())
                .createTime(articleDo.getCreateTime())
                .updateTime(articleDo.getUpdateTime())
                .summary(articleDo.getSummary())
                .readNum(articleDo.getReadNum())
                .build();

        // 查询正文
        ArticleContentDo articleContentDo = articleContentMapper.selectByArticleId(articleId);
        String content = MarkdownEscapedUtil.escaped(articleContentDo.getContent());
        // 将内容转换为html
//        try (FileWriter writer = new FileWriter("D:\\文档\\" + articleDo.getTitle() + ".md")) {
//            writer.write(articleContentDo.getContent());
//            System.out.println("文件已成功创建在当前工作目录的子目录下。");
//        } catch (IOException e) {
//            System.out.println("写入文件时发生错误: " + e.getMessage());
//        }
        String articleContentForHtml = MarkdownHelper.convertMarkdown2Html(content);
//        try (FileWriter writer = new FileWriter("D:\\文档\\" + articleDo.getTitle() + ".html")) {
//            writer.write(articleContentForHtml);
//            System.out.println("文件已成功创建在当前工作目录的子目录下。");
//        } catch (IOException e) {
//            System.out.println("写入文件时发生错误: " + e.getMessage());
//        }
        // 转入vo
        findArticleDetailRspVo.setContent(articleContentForHtml);
        // 查询分类， 找到该文章所关联的分类
        ArticleCategoryRelDo articleCategoryRelDo = articleCategoryRelMapper.selectByArticleId(articleId);
        CategoryDo categoryDo = CategoryDo.builder().build();
        if (Objects.isNull(articleCategoryRelDo)) {
            log.info("【前台文章服务】 文章id:{} 不存在对应分类关联", articleId);
        } else {
            // 查询文章表
            categoryDo = categoryMapper.selectById(articleCategoryRelDo.getCategoryId());
        }
        //转入vo
        findArticleDetailRspVo.setCategoryName(categoryDo.getName());
        findArticleDetailRspVo.setCategoryId(categoryDo.getId());

        // 查询关联标签
        List<ArticleTagRelDo> articleTagRelDos = articleTagRelMapper.selectByArticleId(articleId);
        List<Long> tagIds = Lists.newArrayList();
        if (Objects.nonNull(articleTagRelDos)) {
            tagIds = articleTagRelDos.stream().map(ArticleTagRelDo::getTagId).collect(Collectors.toList());
        }
        // 查询所有标签
        List<TagDo> tagDos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(tagIds)) tagDos = tagMapper.selectListByTagIds(tagIds);

        // 转入vo
        List<FindTagListRspVo> findTagListRspVos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(tagDos)) {
            findTagListRspVos = tagDos.stream()
                    .map(tagDo -> FindTagListRspVo.builder().id(tagDo.getId()).name(tagDo.getName()).build())
                    .collect(Collectors.toList());

        }
        findArticleDetailRspVo.setTags(findTagListRspVos);

        // 上一篇文章
        ArticleDo preDo = articleMapper.selectPreArticleById(articleId);
        // 下一篇文章
        ArticleDo nextDo = articleMapper.selectNextArticleById(articleId);
        // 计算词数
        Integer wordCount = MarkdownStatsUtil.calculateWordCount(articleContentDo.getContent());
        // 估算阅读时间
        String readTime = MarkdownStatsUtil.calculateReadingTime(wordCount);
        // 转换为vo
        if (Objects.nonNull(preDo)) {
            FindPreNextArticleRspVo preVo = FindPreNextArticleRspVo.builder()
                    .articleId(preDo.getId())
                    .title(preDo.getTitle())
                    .build();

            findArticleDetailRspVo.setPreArticle(preVo);
        }
        if (Objects.nonNull(nextDo)) {
            FindPreNextArticleRspVo nextVo = FindPreNextArticleRspVo.builder()
                    .articleId(nextDo.getId())
                    .title(nextDo.getTitle())
                    .build();

            findArticleDetailRspVo.setNextArticle(nextVo);
        }
        findArticleDetailRspVo.setReadTime(readTime);
        findArticleDetailRspVo.setTotalWords(wordCount);
        // 通过事件订阅，将阅读量+1 发布事件
        applicationEventPublisher.publishEvent(new ReadArticleEvent(this, articleId));
        return Response.success(findArticleDetailRspVo);
    }
}
